package com.lasgana.cx.services;

import java.io.IOException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import lombok.Data;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;

import com.google.appengine.repackaged.com.google.common.collect.Lists;
import com.google.common.base.Splitter;
import com.lasgana.cx.models.Crew;
import com.lasgana.cx.models.Roster;

@Data
public class MasterRosterService {

    private Resource masterRoster;
    private static final Logger LOGGER = LoggerFactory.getLogger(MasterRosterService.class);
    private static final Splitter ROSTER_SPLITTER = Splitter.on('|').trimResults();

    private Map<String, Roster> storage = new HashMap<String, Roster>();
    private String currentCategory;
    private Calendar currentMonth;

    public void processNextMonthRoster() throws IOException {
        POIFSFileSystem fs = new POIFSFileSystem(masterRoster.getInputStream());
        HWPFDocument doc = new HWPFDocument(fs);
        WordExtractor we = new WordExtractor(doc);

        List<String> paragraphs = filterBlankLines(we.getParagraphText());
        processRoster(paragraphs);
        LOGGER.info("Document testing completed");
    }

    /**
     * Removes blank lines and static header text.
     *
     * @param paragraphs
     * @return List<String> with real content
     */
    protected List<String> filterBlankLines(String[] paragraphs) {
        List<String> result = Lists.newArrayList();
        for (String line : paragraphs) {
            line = line.replaceAll("\\cM?\r?\n", "");
            if (line.length() > 50) {
                result.add(line);
            }
        }
        return result;
    }

    /**
     * Process through the real content in blocks.
     *
     * @param paragraphs
     */
    protected void processRoster(List<String> paragraphs) {
        // for (int i = 0; i < paragraphs.size(); i++) {
        for (int i = 0; i < 100; i++) {
            if (isHeaderLine(paragraphs.get(i))) {
                processHeaderLine(paragraphs.get(i));
                i += 5;
            } else {
                processContentLine(paragraphs.get(i), paragraphs.get(i+1),paragraphs.get(i+2));
                i += 3;
            }
        }
    }

    protected boolean isHeaderLine(String line) {
        return StringUtils.startsWith(line, "Category: ");
    }

    /**
     * Set the current category and month for the processor, subsequent roster processing will be using this
     * information.
     *
     * @param line "Category: A BC N I    Schedule month: 06/13   Page 1"
     */
    protected void processHeaderLine(String line) {
        processCurrentCategory(line);
        processCurrentMonth(line);
    }

    private void processCurrentCategory(String line) {
        currentCategory = StringUtils.substringBetween(line, "Category: ", "Schedule").trim();
    }

    private void processCurrentMonth(String line) {
        String month = StringUtils.substringBetween(line, "month: ", "Page").trim();
        currentMonth = Calendar.getInstance();
        currentMonth.set(Calendar.MONTH, Integer.valueOf(month.split("/")[0]) - 1);
        currentMonth.set(Calendar.YEAR, Integer.valueOf("20" + month.split("/")[1]));
    }

    protected void processContentLine(String duty, String spanDuty, String specialDuty) {
        Crew currentCrew = new Crew();
        Roster currentRoster = new Roster(currentMonth);
        processContentDutyLine(duty, currentCrew, currentRoster);
        processContentSpanDutyLine(spanDuty, currentCrew, currentRoster);
        processContentSpecialDutyLine(specialDuty, currentCrew, currentRoster);
        submitRoster(currentRoster);
    }

    protected void processContentDutyLine(String duty, Crew currentCrew, Roster currentRoster) {
        List<String> input = Lists.newArrayList(ROSTER_SPLITTER.split(duty));
        List<String> output = currentRoster.getDuty();

        int numberOfDays = currentMonth.getActualMaximum(Calendar.DAY_OF_MONTH);
        currentCrew.setMailBox(Integer.valueOf(input.get(1)));
        for (int i=2; i < numberOfDays+2; i++) {
            output.add(input.get(i));
        }
    }

    protected void processContentSpanDutyLine(String spanDuty, Crew currentCrew, Roster currentRoster) {
        List<String> input = Lists.newArrayList(ROSTER_SPLITTER.split(spanDuty));
        String rosterName = StringUtils.substringBefore(input.get(1), "PED").trim();
        currentCrew.setRosterName(rosterName);
        currentRoster.setRosterName(rosterName);
    }

    protected void processContentSpecialDutyLine(String specialDuty, Crew currentCrew, Roster currentRoster) {
        List<String> input = Lists.newArrayList(ROSTER_SPLITTER.split(specialDuty));
        List<String> output = currentRoster.getSpecialDuty();

        int numberOfDays = currentMonth.getActualMaximum(Calendar.DAY_OF_MONTH);
        for (int i=2; i < numberOfDays+2; i++) {
            output.add(input.get(i));
        }
    }

    protected void submitRoster(Roster roster) {
        storage.put(roster.getRosterName(), roster);
    }
}
